import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import * as colors from 'colors';
import * as moment from 'moment';
import { Between, DeleteResult, Like, Repository } from 'typeorm';
import { SortType } from '../../common/constants/common.constant';
import { LogLevel } from '../constants/log.constant';
import { HttpMethod } from '../constants/user-activity-log.constant';
import { UserActivityLogEntity } from '../entities/user-activity-log.entity';

@Injectable()
export class UserActivityLogService {
  constructor(
    @InjectRepository(UserActivityLogEntity)
    private readonly userActivityLogRepository: Repository<UserActivityLogEntity>
  ) {}
  /**
   * 信息级别用户活动日志
   * @param method HTTP请求方法
   * @param url 请求URL
   * @param requestMessage 请求信息
   * @param responseCode 返回状态码
   * @param responseMessage 返回信息
   * @param interval 请求执行时间
   * @param ip 请求来源IP
   * @param operator 操作人Uuid
   */
  async info(method: HttpMethod, url: string, requestMessage: string, responseCode: number, responseMessage: string, interval: number, ip?: string, operator?: string) {
    console.log(
      colors.green(`[${moment().format('YYYY-MM-DD HH:mm:ss')}] [INFO] - [${method + ' ' + url}] - Request params: ${requestMessage} Response: ${responseCode} - ${responseMessage}  +${interval}ms`)
    );

    return this.create(LogLevel.info, method, url, requestMessage, responseCode, responseMessage, interval, ip, operator);
  }

  /**
   * 警告级别用户活动日志
   * @param method HTTP请求方法
   * @param url 请求URL
   * @param requestMessage 请求信息
   * @param responseCode 返回状态码
   * @param responseMessage 返回信息
   * @param interval 请求执行时间
   * @param ip 请求来源IP
   * @param operator 操作人Uuid
   */
  async warn(method: HttpMethod, url: string, requestMessage: string, responseCode: number, responseMessage: string, interval: number, ip?: string, operator?: string) {
    console.log(
      colors.yellow(`[${moment().format('YYYY-MM-DD HH:mm:ss')}] [WARN] - [${method + ' ' + url}] - Request params: ${requestMessage} Response: ${responseCode} - ${responseMessage}  +${interval}ms`)
    );

    return this.create(LogLevel.warn, method, url, requestMessage, responseCode, responseMessage, interval, ip, operator);
  }

  /**
   * 错误级别用户活动日志
   * @param method HTTP请求方法
   * @param url 请求URL
   * @param requestMessage 请求信息
   * @param responseCode 返回状态码
   * @param responseMessage 返回信息
   * @param interval 请求执行时间
   * @param ip 请求来源IP
   * @param operator 操作人Uuid
   */
  async error(method: HttpMethod, url: string, requestMessage: string, responseCode: number, responseMessage: string, interval: number, ip?: string, operator?: string) {
    console.log(
      colors.red(`[${moment().format('YYYY-MM-DD HH:mm:ss')}] [ERROR] - [${method + ' ' + url}] - Request params: ${requestMessage} Response: ${responseCode} - ${responseMessage}  +${interval}ms`)
    );

    return this.create(LogLevel.error, method, url, requestMessage, responseCode, responseMessage, interval, ip, operator);
  }

  /**
   * 严重错误级别用户活动日志
   * @param method HTTP请求方法
   * @param url 请求URL
   * @param requestMessage 请求信息
   * @param responseCode 返回状态码
   * @param responseMessage 返回信息
   * @param interval 请求执行时间
   * @param ip 请求来源IP
   * @param operator 操作人Uuid
   */
  async fatal(method: HttpMethod, url: string, requestMessage: string, responseCode: number, responseMessage: string, interval: number, ip?: string, operator?: string) {
    console.log(
      colors.magenta(`[${moment().format('YYYY-MM-DD HH:mm:ss')}] [FATAL] - [${method + ' ' + url}] - Request params: ${requestMessage} Response: ${responseCode} - ${responseMessage}  +${interval}ms`)
    );

    return this.create(LogLevel.fatal, method, url, requestMessage, responseCode, responseMessage, interval, ip, operator);
  }

  /**
   * 创建用户活动日志
   * @param level 日志级别
   * @param method HTTP请求方法
   * @param url 请求URL
   * @param requestMessage 请求信息
   * @param responseCode 返回状态码
   * @param responseMessage 返回信息
   * @param interval 请求执行时间
   * @param ip 请求来源IP
   * @param operator 操作人Uuid
   */
  async create(
    level: LogLevel,
    method: HttpMethod,
    url: string,
    requestMessage: string,
    responseCode: number,
    responseMessage: string,
    interval: number,
    ip?: string,
    operator?: string
  ): Promise<UserActivityLogEntity> {
    const activityLog = new UserActivityLogEntity();
    activityLog.level = level;
    activityLog.method = method;
    activityLog.url = url;
    activityLog.requestMessage = requestMessage;
    activityLog.responseCode = responseCode;
    activityLog.responseMessage = responseMessage;
    activityLog.interval = interval;
    activityLog.ip = ip;
    activityLog.userUuid = operator;

    return this.userActivityLogRepository.save(activityLog);
  }

  /**
   * 批量删除活动日志
   * @param idList 日志编号列表
   */
  async deleteAll(idList?: number[]): Promise<DeleteResult> {
    if (idList && idList.length > 0) return this.userActivityLogRepository.delete(idList);
    else {
      return this.userActivityLogRepository.createQueryBuilder('user_activity_logs').delete().execute();
    }
  }

  /**
   * 分页获取用户活动日志列表
   * @param pageIndex 页码
   * @param pageSize 每页数量
   * @param orderBy 排序依据
   * @param sortType 正序or倒序
   * @param start 查询开始时间
   * @param end 查询结束时间
   * @param level 日志级别
   * @param method http方法
   * @param url 请求url，支持模糊搜索
   * @param requestMessage 请求信息，支持模糊搜索
   * @param keyword 请求信息/请求url，支持模糊搜索
   */
  async findAndPaging(
    pageIndex: number,
    pageSize: number,
    orderBy: string,
    sortType: SortType,
    start: Date,
    end: Date,
    level?: LogLevel,
    method?: HttpMethod,
    url?: string,
    requestMessage?: string,
    keyword?: string
  ): Promise<[UserActivityLogEntity[], number]> {
    return this.userActivityLogRepository.findAndCount({
      where: Object.assign(
        { createdAt: Between(start, end) },
        level ? { level } : {},
        method ? { method } : {},
        url ? { url: Like(`%${url}%`) } : {},
        requestMessage ? { requestMessage: Like(`%${requestMessage}%`) } : {},
        keyword ? { url: Like(`%${keyword}%`), requestMessage: Like(`%${keyword}%`) } : {}
      ),
      order: { [orderBy]: sortType },
      skip: pageIndex * pageSize,
      take: pageSize
    });
  }
}
